/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package control;

import DAO.ClienteDAO;
import Entidad.Cliente;
import java.sql.Connection;
import java.sql.Date;
import java.sql.SQLException;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.TreeSet;

/**
 *
 * @author Juan
 */
public class ControlCliente {
    
    ClienteDAO clienteDAO = new ClienteDAO();
    
    private int validarCampos(Cliente cliente) throws Exception{
        ConexionDB conexionBaseDeDatos = new ConexionDB();
        Connection conexion = conexionBaseDeDatos.establecerConexion();
        try {
            String nombre = cliente.getNombre();
            
            if (nombre.length() - numeroEspaciosEnBlanco(nombre) < 3) {
                throw new Exception("El nombre del cliente debe tener al menor tres caracteres.");
            } else if (cliente.getIdentificacion().length() == 0) {
                throw new Exception("Se debe ingresar una identificación para el cliente.");
            } else if (!contieneSoloNumeros(cliente.getIdentificacion())){
                throw new Exception("La identificación del cliente debe contener solo números");
            } else if (clienteDAO.existeCliente(nombre, conexion)) {
                throw new Exception("El nombre del cliente ya existe en la base de datos.");
            } else if (clienteDAO.existeIdentificacion(cliente.getIdentificacion(), conexion)) {
                throw new Exception("El documento especificado ya existe en la base de datos.");
            } else if (cliente.getTelefonos().length() < 7) {
                throw new Exception("Se debe ingresar un teléfono válido como mínimo.");
            } else if (!contieneSoloNumeros(cliente.getTelefonos())) {
                throw new Exception("El campo teléfonos debe contener solo números.");
            } else if (cliente.getDireccion().length() == 0) {
                throw new Exception("Se debe ingresar la dirección del cliente.");
            } else if (cliente.getCiudad().length() == 0) {
                throw new Exception("Se debe ingresar la ciudad en la que reside el cliente.");
            } else if (!contieneSoloNumeros(cliente.getTelefonosCertificados())) {
                throw new Exception("El campo teléfonos de solicitud de certificados "
                        + "de retenciones debe contener solo números.");
            } else if (!contieneSoloNumeros(cliente.getFax())) {
                throw new Exception("El campo fax debe contener solo números.");
            } else if (!cliente.getCorrespondencia() && !cliente.getDevolucionMuestras()
                    && !cliente.getEnvioResultados() && !cliente.getFacturacion()) {
                throw new Exception("Se debe seleccionar al menos una opción para el "
                        + "campo dirección.");
            }
            
            return 0;
        } finally {
            conexion.close();
        }
    }
    
    private int numeroEspaciosEnBlanco(String cadena){
        int contador = 0;
        if(cadena != null){
            for (int i = 0; i < cadena.length(); i++) {
                if(Character.isWhitespace(cadena.charAt(i))) contador++;
            }
        }
        return contador;
    }
    
    private boolean contieneSoloNumeros(String cadena){
        boolean resultado = true;
        if(cadena != null){        
            for (int i = 0; i < cadena.length() && resultado; i++) {
                if(!Character.isDigit(cadena.charAt(i))) resultado = false;
            }
        }
        return resultado;
    }
    
    private String crearAbreviatura(Cliente cliente) throws Exception{
        String abreviatura;
        String nombre = cliente.getNombre();
        String[] palabras = nombre.split(" ");
        int numeroPalabras = palabras.length;
        
        switch(numeroPalabras){
            case 2:
                if(palabras[0].length() > 1)
                    abreviatura = palabras[0].substring(0, 2) + palabras[1].substring(0, 1);
                else
                    abreviatura = palabras[0].substring(0, 1) + palabras[1].substring(0, 2);
                break;
            case 1:
                abreviatura = palabras[0].substring(0, 3);
                break;
            default: //3 o más palabras
                abreviatura = palabras[0].substring(0, 1) +
                        palabras[1].substring(0, 1) + palabras[2].substring(0, 1);
                break;
        }
        
        abreviatura = abreviatura.toUpperCase();
        
        /*Hay que buscar una abreviatura que no exista en la base de datos.
        * Empezamos por la última letra, cambiándola hasta que encontremos un valor que
        * no exista o hayamos probado todos los valores posibles. Si esto último ocurre
        * pasamos a la segunda letra y luego a la primera si pasamos de nuevo por todos los
        * valores.
        */
        
        ConexionDB conexionBaseDeDatos = new ConexionDB();
        try (Connection conexion = conexionBaseDeDatos.establecerConexion()) {
            int posicion = 2;
            char letraActual = abreviatura.charAt(posicion);
            
            while(existeAbreviatura(abreviatura,conexion) && posicion >= 0){            
                char siguienteLetra = siguienteCaracter(abreviatura.charAt(posicion));
                
                char[] abreviaturaAntigua = abreviatura.toCharArray();
                abreviaturaAntigua[posicion] = siguienteLetra;
                abreviatura = String.valueOf(abreviaturaAntigua);
                
                if(siguienteLetra == letraActual){
                    posicion--;
                    if(posicion > -1) letraActual = abreviatura.charAt(posicion);
                }
            }
            
            if(existeAbreviatura(abreviatura,conexion)){
                conexion.close();
                throw new Exception("No se puede crear una abreviatura única para este cliente.");
            }
            
            conexion.close();
        }
        
        return abreviatura;
    }
    
    private boolean existeAbreviatura(String abreviatura, Connection conexion) throws SQLException{
        return clienteDAO.existeAbreviatura(abreviatura, conexion);
    }
    
    private char siguienteCaracter(char caracter){
        //caracter debe ser mayúscula
        if(caracter == 'Z') return 'A';
        else if(caracter == 'Ñ') return 'O';
        else if(caracter == '9') return '0';
        else return (char) (caracter + 1);
    }
    
    public boolean registrarCliente(Cliente cliente) throws Exception{
        boolean resultado = true;
        int validacion = validarCampos(cliente);
        
        if(validacion != 0) resultado = false;
        else{
            String abreviatura = crearAbreviatura(cliente);
            cliente.setAbreviatura(abreviatura);
            
            ConexionDB conexionBaseDeDatos = new ConexionDB();
            Connection conexion = conexionBaseDeDatos.establecerConexion();
            
            clienteDAO.create(cliente, conexion);
        }
        return resultado;
    }
    
    private List<Cliente> cargarListaClientes() throws SQLException{
        ConexionDB conexionBaseDeDatos = new ConexionDB();
        Connection conexion = conexionBaseDeDatos.establecerConexion();
        
        return clienteDAO.loadAll(conexion);
    }
    
    public String[] crearListaNombres() throws SQLException{
        String [] nombresClientes;
        List<Cliente> listaClientes = cargarListaClientes();
        Collection<String> treeSet = new TreeSet<>(Collator.getInstance());
        
        if(listaClientes != null && listaClientes.size() > 0){
            for (int i=0; i<listaClientes.size(); i++)
                treeSet.add(listaClientes.get(i).getNombre());

            nombresClientes = new String[treeSet.size()];
            treeSet.toArray(nombresClientes);
        }else{
            nombresClientes = null;
        }
        
        return nombresClientes;
    }
    
    public int buscarIDCliente(String nombreCliente) throws Exception{
        ConexionDB conexionBaseDeDatos = new ConexionDB();
        Connection conexion = conexionBaseDeDatos.establecerConexion();
        
        int id = clienteDAO.buscarIDCliente(nombreCliente, conexion);
        
        conexion.close();
        
        if(id == 0) throw new Exception("No se encontró la ID de este cliente.");
        
        return id;
    }
    
    public int seleccionarUltimaMuestra(int IDCliente) throws SQLException, Exception{
        ConexionDB conexionBaseDeDatos = new ConexionDB();
        try (Connection conexion = conexionBaseDeDatos.establecerConexion()) {
            int ultimaMuestra = clienteDAO.seleccionarUltimaMuestra(IDCliente, conexion);
            conexion.close();
            return ultimaMuestra;
        }
    }
    
    public void actualizarUltimaMuestra(int IDCliente, int ultimaMuestra) throws SQLException, Exception{
        ConexionDB conexionBaseDeDatos = new ConexionDB();
        try (Connection conexion = conexionBaseDeDatos.establecerConexion()) {
            clienteDAO.actualizarUltimaMuestra(IDCliente, ultimaMuestra, conexion);
            conexion.close();
        }
    }
    
    public Cliente cargarCliente (int IDCliente) throws SQLException {
        ConexionDB conexionBaseDeDatos = new ConexionDB();
        Cliente cliente = new Cliente();
        cliente.setIdCliente(IDCliente);
        try (Connection conexion = conexionBaseDeDatos.establecerConexion()) {
            cliente = clienteDAO.load(cliente, conexion);
            conexion.close();
            return cliente;
        }
    }
    
    public Cliente cargarCliente (String abreviatura) throws SQLException {
        ConexionDB conexionBaseDeDatos = new ConexionDB();
        Cliente cliente = new Cliente();
        cliente.setAbreviatura(abreviatura);
        try (Connection conexion = conexionBaseDeDatos.establecerConexion()) {
            cliente = clienteDAO.eoncontrarClientePorAbreviatura(abreviatura, conexion);
            conexion.close();
            return cliente;
        }
    }
    
    public ArrayList<Cliente> buscarClientes(Cliente cliente, Date fechaInicial, Date fechaFinal) throws Exception{
        ConexionDB conexionBaseDeDatos = new ConexionDB();
        try (Connection conexion = conexionBaseDeDatos.establecerConexion()) {
            ArrayList<Cliente> clientes = clienteDAO.buscarClientes(cliente, fechaInicial, fechaFinal, conexion);
            conexion.close();
            return clientes;
        }
    }

    public ArrayList<Cliente> cargarTodos() throws SQLException {
        ConexionDB conexionBaseDeDatos = new ConexionDB();
        try (Connection conexion = conexionBaseDeDatos.establecerConexion()) {
            ArrayList<Cliente> clientes = (ArrayList<Cliente>) clienteDAO.loadAll(conexion);
            conexion.close();
            return clientes;
        }
    }
    
}
